package com.nononsenseapps.feeder.model.opml

import android.content.Context
import android.net.Uri
import com.nononsenseapps.feeder.db.room.AppDatabase
import com.nononsenseapps.feeder.db.entity.Feed
import com.nononsenseapps.feeder.parser.opml.OPMLParserToDatabase
import com.nononsenseapps.feeder.parser.opml.OPMLToRoom
import com.nononsenseapps.feeder.parser.opml.OpmlParser
import com.nononsenseapps.feeder.parser.opml.writeOutputStream
import com.nononsenseapps.feeder.util.makeToast
import com.nononsenseapps.feeder.worker.requestFeedSync
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import timber.log.Timber
import kotlin.system.measureTimeMillis

/**
 * Exports OPML on a background thread
 */
suspend fun exportOpml(appContext: Context, uri: Uri) {
    try {
        val time = measureTimeMillis {
            appContext.contentResolver.openOutputStream(uri)?.let {
                writeOutputStream(it,
                        tags(appContext),
                        feedsWithTags(appContext))
            }
        }
        Timber.d("Exported OPML in $time ms on ${Thread.currentThread().name}")
    } catch (e: Throwable) {
        //e.printStackTrace()
        Timber.e("Failed to export OMPL: $e")
        withContext(Dispatchers.Main) {
            appContext.makeToast("Failed to export OMPL")
        }
    }
}

/**
 * Imports OPML on a background thread
 */
suspend fun importOpml(context: Context, uri: Uri) {
    val appContext = context.applicationContext
    val db = AppDatabase.getInstance(context)
    try {
        val time = measureTimeMillis {
            val parser = OpmlParser(OPMLToRoom(db))
            appContext.contentResolver.openInputStream(uri).use {
                it?.let { stream ->
                    parser.parseInputStream(stream)
                }
            }
            requestFeedSync(context = context,parallell = true, ignoreConnectivitySettings = false)
        }
        Timber.d("Imported OPML in $time ms on ${Thread.currentThread().name}")
    } catch (e: Throwable) {
        Timber.e( "Failed to import OMPL: $e")
        withContext(Dispatchers.Main) {
            appContext.makeToast("Failed to import OMPL")
        }
    }
}

suspend fun openOpml(context: Context, uri: Uri):List<Feed> {
    val appContext = context.applicationContext
    val retList= mutableListOf<Feed>()
    try {
        val time = measureTimeMillis {
            val parser = OpmlParser(object :
                OPMLParserToDatabase {
                override fun getFeed(url: String): Feed? {
                    return null
                }

                override fun saveFeed(feed: Feed) {
                    retList.add(feed)
                }
            })
            appContext.contentResolver.openInputStream(uri).use {
                it?.let { stream ->
                    parser.parseInputStream(stream)
                }
            }
        }
        Timber.d("Imported OPML in $time ms on ${Thread.currentThread().name}")
    } catch (e: Throwable) {
        Timber.e( "Failed to import OMPL: $e")
        withContext(Dispatchers.Main) {
            appContext.makeToast("Failed to import OMPL")
        }
    }
    return retList
}

fun tags(context: Context): Iterable<String> =
        AppDatabase.getInstance(context).feedDao().loadTags()

fun feedsWithTags(context: Context): (String) -> Iterable<Feed> {
    val dao = AppDatabase.getInstance(context).feedDao()
    return { tag ->
        dao.loadFeeds(tag = tag)
    }
}
